import { Chat, ChatMessage } from 'components/Chat';
import React from 'react';
import { JSONObject } from 'admin/schema/common';
import { CallTaskInfoMsg, DiaogueMsg } from 'admin/schema/SocketMessage';
import { ManListenCall, ManListenCallSession } from 'admin/schema/Task';
import { getSocket } from 'servers/socket';

import qs from 'query-string';
import { getStateDom } from '../../components/TaskTool';
import { filterDialogue, webDebug } from 'utils/tools';

interface ManualListenProp {
  taskId: number;
}

interface ManualListenState extends ManualListenProp {
  /**
   * 模块页面数据
   */
  callInfo?: ManListenCall;
  /**
   * 当前展示的两组聊天的数据记录
   */
  currentRecord: ManListenCallSession[];
  /**
   * 左右两个回话窗口的激活状态
   */
  containerActive: 0 | 1;
}

export class ManualListen extends React.Component<ManualListenProp, ManualListenState> {
  /**
   * 下次切换通话记录时切换的哪一项聊天框
   */
  private currentIndex: 0 | 1;

  /**
   * 两个回话记录控件的引用集
   */
  private refGroup: React.RefObject<any>[];

  /**
   * 聊天缓存
   * 在实际业务中，可能会同时有很多呼叫/通话，但是界面上只有两个聊天回话窗口，记录一个缓存将收到的但是不能渲染到界面的会话消息保存起来，已保证切换聊天窗口后信息的完整度
   */
  private chatCache: Map<string, ChatMessage[]>;

  /**
   * 当前处于active状态的callId
   */
  private activeId: string;

  constructor(prop: ManualListenProp) {
    super(prop);
    this.chatCache = new Map();
    this.activeId = '';
    const chatRef1 = React.createRef<any>();
    const chatRef2 = React.createRef<any>();
    this.refGroup = [chatRef1, chatRef2];
    this.currentIndex = 1;
    this.state = {
      ...prop,
      containerActive: 0,
      callInfo: {
        taskId: 1,
        countComplete: 1000,
        countProcess: 1000,
        sessions: [],
      },
      currentRecord: [],
    };
  }

  componentDidMount() {
    this.addSocketEvent();
    this.setState(
      {
        currentRecord: [
          this.state.callInfo?.sessions[0] as ManListenCallSession,
          this.state.callInfo?.sessions[1] as ManListenCallSession,
        ],
      },
      () => {
        this.forceUpdate();
      }
    );
  }
  componentWillUnmount = () => {
    this.removeSocketEvent();
    this.setState = (state, callback) => {
      return;
    };
  };

  /**
   * 绑定socket事件
   * dialogueContentEvent： 获取单句会话消息，渲染至页面
   * callTaskStatusEvent： 获取当前机器人正在 呼叫/通话 的列表并渲染
   */
  private addSocketEvent() {
    console.log('人工监听-推送事件->>>>socket事件-开始');
    const socket = getSocket();
    socket.addEvent('dialogueContentEvent', (data: JSONObject) => {
      this.onReceiveMsg(data as DiaogueMsg);
    });
    socket.addEvent('callTaskStatusEvent', (data: JSONObject) => {
      const currentTaskId = qs.parse(window.location.search).id;
      if (data.taskId.toString() !== currentTaskId) {
        return;
      }
      (data as ManListenCall).sessions.forEach(item => {
        item.callRecordId === this.activeId && (item.active = true);
      });
      this.setState(
        {
          callInfo: data as CallTaskInfoMsg,
          currentRecord: [
            data?.sessions[0] as ManListenCallSession,
            data?.sessions[1] as ManListenCallSession,
          ],
        },
        () => {
          this.forceUpdate();
        }
      );
    });
  }
  /** 卸载socket事件*/
  private removeSocketEvent() {
    console.log('人工监听-推送事件->>>>socket事件-删除');
    const socket = getSocket();
    socket.removeEvent(['dialogueContentEvent', 'callTaskStatusEvent']);
  }
  /**
   * 收到会话的socket消息后，将数据处理一遍格式，转为Chat组件接受的数据格式，渲染会话消息并记录到缓存中
   */
  private onReceiveMsg(data: DiaogueMsg) {
    const cache = this.chatCache;
    const callRecordId = (data as DiaogueMsg).callRecordId;
    const record = cache.get(callRecordId) || [];
    const currentRecord = this.state.currentRecord;
    const speakerMap = {
      '0': 'called',
      '1': 'caller',
      '2': 'man',
    };
    // index为0是开场语
    record.push({
      index: data.index,
      role: speakerMap[data.speaker as '0' | '1' | '2'] as 'called' | 'caller' | 'man',
      message: data.content,
      sound: data.url,
      status: data.status,
      callRecordId,
    });
    // 通话记录拼接后，需要根据index去重
    const newRecord = filterDialogue(record as ChatMessage[]);
    cache.set(callRecordId, newRecord);
    if (!currentRecord[0] && !currentRecord[1]) {
      return;
    }
    const refGroup = this.refGroup;
    if (refGroup.length) {
      refGroup.forEach((ref, index) => {
        // 目标元素：根据callRecordId在聊天记录中查找过滤
        if (ref.current?.getCallRecordId() === callRecordId) {
          ref.current?.setRecord(newRecord);
        }
      });
    }
  }

  /**
   * 切换当前记录展示项
   * 职能：
   * 1. 将左侧通话列表的某一项激活展开
   * 2. 查找激活项是否存在聊天窗口，若存在只需要高亮右侧窗口，不存在就切换激活窗口
   */
  private activeItem(item: ManListenCallSession, index: number): void {
    this.activeId = item.callRecordId.toString();
    // 在右侧窗口，查找跟tab相同的callRecordId，高亮
    this.refGroup.forEach((ref, index) => {
      const callRecordId = ref.current?.getCallRecordId();
      if (callRecordId === item.callRecordId) {
        this.setState({
          containerActive: index as 0 | 1,
        });
        return;
      }
    });
    // 当前右侧没有展示对应通话内容，需要替换显示（替换逻辑？？？）
    const copySession = this.state.callInfo?.sessions;
    copySession?.forEach(item => {
      item.active = false;
    });

    item.active = true;
    copySession?.splice(index, 1, item);
    const { callInfo } = this.state;
    (callInfo as any).sessions = copySession;

    const nextIndex: 0 | 1 = this.currentIndex === 1 ? 0 : 1;
    this.currentIndex = nextIndex;

    const copyCurrentRecord = this.state.currentRecord;
    copyCurrentRecord[nextIndex] = item;

    this.refGroup[this.currentIndex].current?.setRecord(
      this.chatCache.get(item.callRecordId) || []
    );
    this.setState(
      {
        containerActive: nextIndex,
        callInfo: callInfo,
        currentRecord: copyCurrentRecord,
      },
      () => {
        this.forceUpdate();
      }
    );
  }

  /**
   * 根据callRecordId获得一段对话
   */
  private getChatMsg(callRecordId: string): ChatMessage[] {
    return this.chatCache.get(callRecordId) || [];
  }

  /**
   * Chat组件点击查看历史后，将历史会话信息填入缓存中
   */
  private onGetHistory(msg: ChatMessage[], callRecordId: string, callSerialNumber: string): void {
    const currentRecord = this.state.currentRecord;
    this.chatCache.set(callRecordId, msg);
    if (!currentRecord[0] && !currentRecord[1]) {
      return;
    }
    const aimRef = currentRecord.find(item => item && item.callRecordId === callRecordId);
    if (aimRef) {
      const i = currentRecord.indexOf(aimRef);
      this.refGroup[i].current?.setRecord(msg);
    }
  }

  render() {
    const { callInfo, currentRecord, containerActive } = this.state;
    if (currentRecord.length === 0) {
      return <></>;
    }
    const [chatRef1, chatRef2] = this.refGroup;
    const chatInfo = currentRecord[0];
    const chatInfoSec = currentRecord[1];
    const session = callInfo?.sessions;

    return (
      <div className="manlisten">
        <div className="manlisten-callrecord">
          <span className="manlisten-incall">
            通话中{session?.filter(item => item.state === 3).length}
          </span>
          <span className="manlisten-waitcall">
            呼叫中{session?.filter(item => item.state === 1).length}
          </span>
          {callInfo?.sessions &&
            callInfo.sessions.map((item, index) => {
              if (item.active) {
                return (
                  <div className="manlisten-call-item active" key={index}>
                    <div className="manlisten-callitem-header">
                      <span className="manlisten-callitem-callednum">
                        {item.number}
                        {webDebug && <b className="debug-style">【{item.callRecordId}】</b>}
                      </span>
                      <span className="manlisten-callitem-state">{getStateDom(item.state)}</span>
                    </div>
                    {item.answerTime && (
                      <div className="manlisten-callitem-ringtime">
                        <span className="manlisten-callitem-label">接通时间</span>
                        <span>{item.answerTime}</span>
                      </div>
                    )}
                    <div className="manlisten-callitem-calledname">
                      <span className="manlisten-callitem-label">被叫姓名</span>
                      <span>{item.calledName}</span>
                    </div>
                    <div className="manlisten-callitem-remark">
                      <span className="manlisten-callitem-label">被叫备注</span>
                      <span>{item.calledRemarks}</span>
                    </div>
                  </div>
                );
              } else {
                return (
                  <div
                    className="manlisten-call-item notactive"
                    key={index}
                    onClick={() => {
                      this.activeItem(item, index);
                    }}
                  >
                    <div className="manlisten-callitem-header">
                      <span className="manlisten-callitem-callednum">
                        {item.number}
                        {webDebug && <b className="debug-style">【{item.callRecordId}】</b>}
                      </span>
                      <span className="manlisten-callitem-state">{getStateDom(item.state)}</span>
                    </div>
                  </div>
                );
              }
            })}
        </div>
        {chatInfo && (
          <div
            className={`manlisten-chat-left ${
              containerActive === 0 ? 'chat-container-active' : null
            }`}
          >
            <Chat
              showHistoryLink={true}
              ref={chatRef1}
              callSerialNumber={chatInfo.callSerialNumber}
              callRecordId={chatInfo.callRecordId}
              centerCallId={chatInfo.callId}
              phoneNum={chatInfo.number}
              status={chatInfo.state}
              messages={this.getChatMsg(chatInfo.callRecordId)}
              onGetHistory={this.onGetHistory.bind(this)}
            />
          </div>
        )}
        {chatInfoSec && (
          <div
            className={`manlisten-chat-right ${
              containerActive === 1 ? 'chat-container-active' : null
            }`}
          >
            <Chat
              showHistoryLink={true}
              ref={chatRef2}
              callSerialNumber={chatInfo.callSerialNumber}
              centerCallId={chatInfoSec.callId}
              callRecordId={chatInfoSec.callRecordId}
              phoneNum={chatInfoSec.number}
              status={chatInfoSec.state}
              messages={this.getChatMsg(chatInfoSec.callRecordId)}
              onGetHistory={this.onGetHistory.bind(this)}
            />
          </div>
        )}
      </div>
    );
  }
}
